from abc import ABC, abstractmethod
from typing import Any, Dict, Iterable, Optional

from aicenter.models import AIInstance, AIModel
from ._error import AIModelRegistrationError


class AIClient(ABC):
    """
    抽象 AI 客户端
    """

    def __init__(self, instance: AIInstance, *models: AIModel):
        """
        创建 AI 客户端实例

        :param instance: AI 实例对象
        """
        self._name: str = instance.name
        self._app_id: str = instance.app_id
        self._api_key: str = instance.api_key
        self._api_secret: str = instance.api_secret
        self._models: Dict[int, AIModel] = {model.id: model for model in models}
        # 初始化子类
        self._initialize(instance.instance_params)

    @property
    def name(self) -> str:
        """AI 实例名称"""
        return self._name

    @property
    def app_id(self) -> str:
        """应用 ID"""
        return self._app_id

    @property
    def api_key(self) -> str:
        """接口 KEY"""
        return self._api_key

    @property
    def api_secret(self) -> str:
        """接口密钥"""
        return self._api_secret

    @property
    def models(self) -> Iterable[AIModel]:
        return self._models.values()

    def register_model(self, model: AIModel) -> None:
        """
        注册 AI 模型

        若注册失败，将抛出 AIModelRegistrationError 异常

        :param model: AI 模型对象
        """
        # 调用子类的注册函数，若子类注册模型失败，则抛出错误
        if not self._register_model(model):
            raise AIModelRegistrationError(model)
        # 若注册成功，则绑定该模型
        self._models[model.id] = model

    @staticmethod
    def _get_parameter(name: str, *params_array: Optional[dict]) -> Optional[Any]:
        """
        依次尝试每一个参数集合，直到获取到第一个存在的参数；
        若所有参数集合都不存在指定参数，则返回 None。

        :param name: 参数名
        :param default: 参数默认值
        :param params_array: 参数集数组
        :return: 返回参数值
        """
        for params in params_array:
            if params is not None and name in params:
                return params[name]
        return None

    @abstractmethod
    def _initialize(self, params: dict) -> None:
        """
        初始化 AI 客户端

        :param params: 实例参数
        """
        pass

    @abstractmethod
    def _register_model(self, model: AIModel) -> bool:
        """
        注册 AI 模型

        :param model: AI 模型
        :return: 若返回 False，则表示注册失败
        """
        pass
